package com.glsc.ngateway.oaflow.service.xirtrade;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.api.common.enums.GatewayConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.xirtrade.TOaFlowXirTradeInfo;
import com.glsc.ngateway.common.xir.domain.*;
import com.glsc.ngateway.common.api.common.dto.AppendIdDto;
import com.glsc.ngateway.common.api.oaflow.dto.xirtrade.TOaFlowXirTradeConfigDto;
import com.glsc.ngateway.common.api.oaflow.dto.xirtrade.TOaFlowXirTradeConfigSearchParamDto;
import com.glsc.ngateway.common.api.oaflow.dto.xirtrade.TOaFlowXirTradeInfoZJYYBDto;
import com.glsc.ngateway.common.base.enums.OaFlowXirTradeInfoStatusEnum;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowXirTradeInfoRepository;
import com.glsc.ngateway.common.xir.repo.*;
import com.glsc.ngateway.oaflow.exception.OaflowException;
import com.glsc.ngateway.oaflow.service.AppendixService;
import com.glsc.ngateway.oaflow.service.FlowService;
import com.glsc.ngateway.oaflow.service.xirtrade.enums.XirTradeOaFlowTypeEnum;
import com.glsc.ngateway.oaflow.service.xirtrade.enums.XirTtrdOtcTradeOrdStatusEnum;
import com.glsc.ngateway.oaflow.service.xirtrade.enums.衡泰业务类型枚举_资金运营部;
import com.google.common.collect.Lists;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Component
public class XirTradeZJYYBFactory extends AbstractXirTradeFactory {

    private static Logger logger = LoggerFactory.getLogger(TOaFlowXirTradeService.class);
    private static TtrdOtcTradeRepository otcTradeRepo;
    private static TtrdSetInstructionRepository instructionRepo;
    private static TOaFlowXirTradeInfoRepository xirTradeInfoRepo;
    private static FlowService flowService;
    private static AppendixService appendixService;
    private static TtrdOtcIblbRepository iblbRepo;
    private static TtrdOtcCounterpartyRepository counterpartyRepo;
    private static TOaFlowXirTradeService xirTradeService;
    private static TtrdOtcPledgebondRepository ttrdOtcPledgebondRepository;
    private static TbndRepository tbndRepository;


    @Override
    public String getType() {
        return "资金运营部";
    }

    /**
     * 配方表Map<衡泰业务类别，生产步骤>
     * 一般为查找需要同步的数据->查询相关数据->生成同步数据
     * TODO:为减少连接查询衡泰数据库次数，去掉配方表，将所有业务类型做聚合，按统一逻辑处理
     */
    private static final Map<衡泰业务类型枚举_资金运营部, List<Consumer<BuildContext>>> FORMULA_MAP = new HashMap<>() {{
        put(衡泰业务类型枚举_资金运营部.同业拆借_拆入_首期, List.of(
                XirTradeZJYYBFactory::buildTrade,
                XirTradeZJYYBFactory::fiterSynced,
                XirTradeZJYYBFactory::buildIblb,
                XirTradeZJYYBFactory::buildParty,
                XirTradeZJYYBFactory::fit));
        put(衡泰业务类型枚举_资金运营部.同业拆借_拆入_到期还款, List.of(
                XirTradeZJYYBFactory::buildInst,
                XirTradeZJYYBFactory::buildTrade,
                XirTradeZJYYBFactory::fiterSynced,
                XirTradeZJYYBFactory::buildIblb,
                XirTradeZJYYBFactory::buildParty,
                XirTradeZJYYBFactory::fit
        ));
        put(衡泰业务类型枚举_资金运营部.债券认购_分销买入_首期, List.of(
                XirTradeZJYYBFactory::buildTrade,
                XirTradeZJYYBFactory::fiterSynced,
                XirTradeZJYYBFactory::buildParty,
                XirTradeZJYYBFactory::fit
        ));
        put(衡泰业务类型枚举_资金运营部.逆回购_首期, List.of(
                XirTradeZJYYBFactory::buildInst,
                XirTradeZJYYBFactory::buildTrade,
                XirTradeZJYYBFactory::fiterRemark,
                XirTradeZJYYBFactory::fiterSynced,
                XirTradeZJYYBFactory::buildIblb,
                XirTradeZJYYBFactory::buildParty,
                XirTradeZJYYBFactory::buildPledgebond,
                XirTradeZJYYBFactory::fit
        ));
    }};

    /**
     * 根据日期查询所有已配置的类别，生成同步过的数据
     * 【重要】为防止并发，只能串行化执行，使用悲观锁
     */
    @Override
    public List<TOaFlowXirTradeInfoZJYYBDto> buildUnsyncTradeInfo(@NotNull String date) {
        //找出所有配置
        List<TOaFlowXirTradeConfigDto> allConfig = xirTradeService.queryAllConfig(
                TOaFlowXirTradeConfigSearchParamDto.builder()
                        .date(date)
                        .workflowTypeList(List.of(XirTradeOaFlowTypeEnum.资金运营部_公司债务融资申请流程.getCode()
                                , XirTradeOaFlowTypeEnum.资金运营部_资金运营部自有资金划付流程.getCode(),
                                XirTradeOaFlowTypeEnum.资金运营部_资金运营部业务交易对手准入流程.getCode())
                        )
                        .build());
        if (CollectionUtil.isEmpty(allConfig)) {
            throw new OaflowException("当前无生效配置");
        }
        List<TOaFlowXirTradeInfoZJYYBDto> res = allConfig.stream()
                .map(config -> {
                    try {
                        衡泰业务类型枚举_资金运营部 bizType = 衡泰业务类型枚举_资金运营部.seek(config.getXirBizType());
                        if (!FORMULA_MAP.containsKey(bizType)) {
                            logger.error("XirTradeFactory生产告警，未找到配方{}，无法生产", bizType.getCode());
                            return null;
                        }
                        //定义上下文
                        BuildContext context = BuildContext.builder()
                                .date(date)
                                .config(config)
                                .bizType(bizType)
                                .build();
                        super.initAccid(context);
                        if (CollectionUtil.isEmpty(context.getCashAccidList()) && CollectionUtil.isEmpty(context.getSecuAccidList())) {
                            logger.error("XirTradeFactory生产告警，配方{}无配置的资金/证券账户，无法生产", bizType.getCode());
                            return null;
                        }
                        //根据业务类别拿到具体配方，根据步骤生产
                        FORMULA_MAP.get(bizType).forEach(step ->
                                step.accept(context)
                        );
                        return context.getRes();
                    } catch (Exception exception) {
                        logger.error("XirTradeFactory生产异常", exception);
                        return null;
                    }
                })
                .filter(CollectionUtil::isNotEmpty)
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        return res;
    }

    /**
     * 从trade表查找数据
     */
    private static void buildTrade(BuildContext context) {
        if (context.getBizType().equals(衡泰业务类型枚举_资金运营部.逆回购_首期)) {
            List<TtrdOtcTrade> tradeList = otcTradeRepo.findAllByTrdtypeAndSetdateAndOrdstatusIn(context.getBizType().getCode(), context.getDate(),
                    List.of(XirTtrdOtcTradeOrdStatusEnum.新建.getCode())
            );

            context.setTradeList(tradeList);
            return;
        }
        if (CollectionUtil.isNotEmpty(context.getInstructionList())) {
            context.setTradeList(otcTradeRepo.findAllByIntordidIn(context.getIntordIdList()));
        } else {
            context.setTradeList(otcTradeRepo.findAllByTrdtypeAndSetdateAndCashAccidInAndSecuAccidInAndOrdstatusIn(context.getBizType().getCode(), context.getDate(), context.getCashAccidList(), context.getSecuAccidList(),
                    context.getBizType().equals(衡泰业务类型枚举_资金运营部.同业拆借_拆入_首期) ?
                            List.of(XirTtrdOtcTradeOrdStatusEnum.成交确认.getCode())
                            : List.of(XirTtrdOtcTradeOrdStatusEnum.审批通过.getCode(), XirTtrdOtcTradeOrdStatusEnum.成交确认.getCode())
            ));
            context.setIntordIdList(CollectionUtil.isEmpty(context.getTradeList()) ? new ArrayList<>(0) : context.getTradeList().stream().map(TtrdOtcTrade::getIntordid).collect(Collectors.toList()));
        }
    }

    /**
     * 从指令表查找数据
     */
    private static void buildInst(BuildContext context) {
        context.setInstructionList(instructionRepo.findAllByBiztypeAndSetdateAndCashAccidInAndSecuAccidIn(context.getBizType().getCode(), context.getDate(), context.getCashAccidList(), context.getSecuAccidList()));
        if (衡泰业务类型枚举_资金运营部.逆回购_首期.getCode().equals(context.getBizType().getCode())) {
            List<TtrdOtcTrade> tradeList = otcTradeRepo.findAllByTrdtypeAndSetdateAndOrdstatusIn(context.getBizType().getCode(), context.getDate(),
                    List.of(XirTtrdOtcTradeOrdStatusEnum.新建.getCode())
            );
            if (CollectionUtil.isNotEmpty(tradeList)) {
                context.setIntordIdList(tradeList.stream().map(TtrdOtcTrade::getIntordid).collect(Collectors.toList()));
            }
        } else {
            context.setIntordIdList(CollectionUtil.isEmpty(context.getInstructionList()) ? new ArrayList<>(0) : context.getInstructionList().stream().map(TtrdSetInstruction::getIntordid).collect(Collectors.toList()));

        }
    }

    /**
     * 过滤备注豁免
     */
    private static void fiterRemark(BuildContext context) {
        List<TtrdOtcTrade> tradeList = context.getTradeList();
        if (CollectionUtil.isNotEmpty(tradeList)) {
            tradeList = tradeList.stream().filter(trade -> trade.getRemark() != null && trade.getRemark().contains("豁免")).collect(Collectors.toList());
            context.setTradeList(tradeList);
        }
    }

    /**
     * 过滤掉已经同步过的
     */
    private static void fiterSynced(BuildContext context) {
        List<String> instIds = new ArrayList<>(0);
        if (CollectionUtil.isNotEmpty(context.getInstructionList())) {
            instIds = context.getInstructionList().stream().map(TtrdSetInstruction::getInstId).collect(Collectors.toList());
        }
        logger.info("1衡泰过滤掉已经同步过的数据context.getTradeList{}", JSON.toJSONString(context.getTradeList()));
        //找所有存在的记录
        //List<TOaFlowXirTradeInfo> existTradeInfoList = xirTradeInfoRepo.findAllByInstIdInAndXirBizTypeAndIntordidIn(instIds, context.getBizType().getCode(), context.getIntordIdList());
        List<TOaFlowXirTradeInfo> existTradeInfoList = Lists.newArrayList();
        if (衡泰业务类型枚举_资金运营部.逆回购_首期.getCode().equals(context.getBizType().getCode())) {
            logger.info("衡泰过滤掉已经同步过的数据参数,biztype={},IntordIdList={}", context.getBizType().getCode(), context.getIntordIdList());
            existTradeInfoList = xirTradeInfoRepo.findAllByXirBizTypeAndIntordidIn(context.getBizType().getCode(), context.getIntordIdList());
            logger.info("衡泰过滤掉已经同步过的数据结果{}", JSON.toJSONString(existTradeInfoList));
        } else {
            existTradeInfoList = xirTradeInfoRepo.findAllByInstIdInAndXirBizTypeAndIntordidIn(instIds, context.getBizType().getCode(), context.getIntordIdList());
        }

        if (衡泰业务类型枚举_资金运营部.逆回购_首期.getCode().equals(context.getBizType().getCode())) {
            //否则直接过滤交易表
            List<String> exixtsList = existTradeInfoList.stream().map(TOaFlowXirTradeInfo::getIntordid).collect(Collectors.toList());
            context.setTradeList(context.getTradeList().stream().filter(t -> !exixtsList.contains(t.getIntordid())).collect(Collectors.toList()));
            context.setIntordIdList(context.getTradeList().stream().map(TtrdOtcTrade::getIntordid).collect(Collectors.toList()));
            logger.info("3.0衡泰过滤掉已经同步过的数据context.getTradeList{}", JSON.toJSONString(context.getTradeList()));
        } else {
            if (CollectionUtil.isNotEmpty(existTradeInfoList)) {
                context.setExistTradeInfoList(existTradeInfoList);
                //如果有指令表，先过滤指令，再根据指令过滤交易
                if (CollectionUtil.isNotEmpty(context.getInstructionList())) {
                    Map<String, String> existInstIdMap = existTradeInfoList.stream().collect(Collectors.toMap(TOaFlowXirTradeInfo::getInstId, TOaFlowXirTradeInfo::getDealStatus));
                    context.setInstructionList(context.getInstructionList().stream()
                            .filter(i -> OaFlowXirTradeInfoStatusEnum.canSync(existInstIdMap.get(i)))
                            .collect(Collectors.toList()));
                    Set<String> newIntordidSet = context.getInstructionList().stream().map(TtrdSetInstruction::getIntordid).collect(Collectors.toSet());
                    context.setIntordIdList(new ArrayList<>(newIntordidSet));
                    context.setTradeList(context.getTradeList().stream()
                            .filter(t -> newIntordidSet.contains(t.getIntordid()))
                            .collect(Collectors.toList()));

                    logger.info("2衡泰过滤掉已经同步过的数据context.getTradeList{}", JSON.toJSONString(context.getTradeList()));
                } else if (CollectionUtil.isNotEmpty(context.getTradeList())) {
                    //否则直接过滤交易表
                    if (衡泰业务类型枚举_资金运营部.逆回购_首期.getCode().equals(context.getBizType().getCode())) {
//                    List<String> exixtsList = existTradeInfoList.stream().map(TOaFlowXirTradeInfo::getIntordid).collect(Collectors.toList());
//                    context.setTradeList(context.getTradeList().stream()
//                            .filter(t -> !exixtsList.contains(t.getIntordid()))
//                            .collect(Collectors.toList()));
                    } else {
                        Map<String, String> existIntordIdMap = existTradeInfoList.stream().collect(Collectors.toMap(TOaFlowXirTradeInfo::getIntordid, TOaFlowXirTradeInfo::getDealStatus));
                        context.setTradeList(context.getTradeList().stream()
                                .filter(t -> !existIntordIdMap.containsKey(t.getIntordid()) || OaFlowXirTradeInfoStatusEnum.canSync(existIntordIdMap.get(t.getIntordid())))
                                .collect(Collectors.toList()));
                    }
                    context.setIntordIdList(context.getTradeList().stream().map(TtrdOtcTrade::getIntordid).collect(Collectors.toList()));
                    logger.info("3衡泰过滤掉已经同步过的数据context.getTradeList{}", JSON.toJSONString(context.getTradeList()));
                }
            }
        }
        logger.info("4衡泰过滤掉已经同步过的数据context.getTradeList{}", JSON.toJSONString(context.getTradeList()));
    }


    private static void buildPledgebond(BuildContext context) {
        if (CollectionUtil.isNotEmpty(context.getTradeList())) {
            List<String> intordidList = context.getTradeList().stream().map(TtrdOtcTrade::getIntordid).collect(Collectors.toList());
            List<TtrdOtcPledgebond> ttrdOtcPledgebondList = ttrdOtcPledgebondRepository.findAllByiCodeIn(intordidList);
            Map<String, List<TtrdOtcPledgebond>> pledgebondMap = ttrdOtcPledgebondList.stream().collect(Collectors.groupingBy(TtrdOtcPledgebond::getICode));
            List<String> piCodeList = ttrdOtcPledgebondList.stream().map(TtrdOtcPledgebond::getPICode).collect(Collectors.toList());
            Map<String, List<Tbnd>> tbndMap = tbndRepository.findAllByICodeIn(piCodeList).stream().collect(Collectors.toMap(Tbnd::getICode,
                    Collections::singletonList,
                    (a, b) -> {
                        List<Tbnd> result = new ArrayList<>(a);
                        result.addAll(b);
                        return result;
                    }));
            context.setPledgebondMap(pledgebondMap);
            context.setTbndMap(tbndMap);
        }
    }

    /**
     * 查找订单信息
     *
     * @param context
     */
    private static void buildIblb(BuildContext context) {
        if (CollectionUtil.isNotEmpty(context.getTradeList())) {
            if (CollectionUtil.isEmpty(context.getIntordIdList())) {
                context.setIntordIdList(context.getTradeList().stream().map(TtrdOtcTrade::getIntordid).collect(Collectors.toList()));
            }
            context.setIblbList(iblbRepo.findAllById(context.getIntordIdList()));
        }
    }

    /**
     * 查找对手信息
     */
    private static void buildParty(BuildContext context) {
        if (CollectionUtil.isNotEmpty(context.getTradeList())) {
            List<String> partyIdList = context.getTradeList().stream().map(TtrdOtcTrade::getPartyid).collect(Collectors.toList());
            context.setPartyList(counterpartyRepo.findAllByPartyidIn(partyIdList));
        }
    }

    /**
     * 组装，虽然对各业务兼容，但仍然需要业务顺序分别进行组装
     */
    private static void fit(BuildContext context) {
        if (CollectionUtil.isEmpty(context.getTradeList())) {
            logger.error("XirTradeFactory生产告警，无可生产列表，type-{}", context.getBizType().getCode());
        } else {
            //对手信息
            Map<String, TtrdOtcCounterparty> partyMap = context.getPartyList().stream().collect(Collectors.toMap(TtrdOtcCounterparty::getPartyid, o -> o, (o1, o2) -> o1));
            //已同步过的
            Map<String, TOaFlowXirTradeInfo> existTradeInfoMap = context.getExistTradeInfoList().stream().collect(Collectors.toMap(TOaFlowXirTradeInfo::getIntordid, o -> o, (o1, o2) -> o1));
            //所有首期（目前只有同业拆入首期）
            Map<String, TOaFlowXirTradeInfo> existFstTradeInfoMap = CollectionUtil.isEmpty(context.getIntordIdList()) ? Collections.EMPTY_MAP :
                    xirTradeInfoRepo.findAllByIntordidInAndXirBizTypeIn(context.getIntordIdList(), List.of(衡泰业务类型枚举_资金运营部.同业拆借_拆入_首期.getCode()))
                            .stream()
                            .collect(Collectors.toMap(TOaFlowXirTradeInfo::getIntordid, o -> o, (o1, o2) -> o1));
            //用于获取期限
            Map<String, TtrdOtcIblb> iblbMap = context.getIblbList().stream().collect(Collectors.toMap(TtrdOtcIblb::getICode, o -> o));
            //指令信息
            Map<String, TtrdSetInstruction> instMap = CollectionUtil.isEmpty(context.getInstructionList()) ? MapUtil.empty() :
                    context.getInstructionList().stream().collect(Collectors.toMap(TtrdSetInstruction::getIntordid, o -> o, (o1, o2) -> o1));
            //交易员预查
            setEmpByTraderList(context);
            context.setRes(
                    context.getTradeList().stream()
                            .map(trade -> {
                                //交易对手
                                TtrdOtcCounterparty party = partyMap.get(trade.getPartyid());
                                //交易对手为临时交易对手时
                                if (!Objects.nonNull(party)){
                                    party = new TtrdOtcCounterparty();
                                    party.setPartyname(trade.getPartynametempority());
                                }
                                Map<String, List<TtrdOtcPledgebond>> pledgebondMap = context.getPledgebondMap();
                                Map<String, List<Tbnd>> tbndMap = context.getTbndMap();
                                //内部交易号Intordid对应的是TTRD_OTC_PLEDGEBOND.I_CODE
                                List<TtrdOtcPledgebond> ttrdOtcPledgebond = pledgebondMap.get(trade.getIntordid());
                                List<Tbnd> tbnd = Lists.newArrayList();
                                if (CollectionUtil.isNotEmpty(ttrdOtcPledgebond)) {
                                    for(TtrdOtcPledgebond item:ttrdOtcPledgebond){
                                        tbnd.addAll(tbndMap.get(item.getPICode()));
                                    }
                                }
                                TOaFlowXirTradeInfoZJYYBDto build = TOaFlowXirTradeInfoZJYYBDto.builder()
                                        .id(existTradeInfoMap.containsKey(trade.getIntordid()) ? existTradeInfoMap.get(trade.getIntordid()).getId() : null)
                                        .dealStatus(OaFlowXirTradeInfoStatusEnum.UNSYNC.getCode())
                                        .workflowId(context.getConfig().getWorkflowId())
                                        .intordid(trade.getIntordid())
                                        .sysordid(trade.getSysordid())
                                        .instId(instMap.containsKey(trade.getIntordid()) ? instMap.get(trade.getIntordid()).getInstId() : trade.getFstInstId())
                                        .xirBizType(context.getBizType().getCode())
                                        .xirBizTypeName(trade.getIName())
                                        .cashAccid(trade.getCashAccid())
                                        .secuAccid(trade.getSecuAccid())
                                        .partyId(trade.getPartyid())
                                        .partyName(Objects.nonNull(party) ? party.getPartyname() : null)
                                        .partyBankCode(trade.getPartyBankCode())
                                        .partyBankAccName(trade.getPartyBankAccName())
                                        .partyAccCode(trade.getPartyBankAccCode())
                                        .partyAccName(trade.getPartyAccName())
                                        .changeAmount(new BigDecimal(trade.getOrdamount()))
                                        .settleBeginDate(trade.getSetdate())
                                        .settleFeeDesc(trade.getIName())
                                        .instIdFirst(trade.getFstInstId())
                                        .instIdEnd(trade.getEndInstId())
                                        //摘要
                                        .bizBrief(trade.getRemark())
//                                        //保存到草稿
//                                        .isnextflow("1")
                                        //标题
                                        .title(Objects.nonNull(party) ? context.getBizType().getTitle(iblbMap.get(trade.getIntordid()), party, trade) : null)
                                        //划款说明
                                        .hksm(Objects.nonNull(party) ? context.getBizType().getHksm(trade, iblbMap.get(trade.getIntordid()), party, ttrdOtcPledgebond, tbnd) : null)
                                        .xqnr(Objects.nonNull(party) ? context.getBizType().getHksm(trade, iblbMap.get(trade.getIntordid()), party, ttrdOtcPledgebond, tbnd) : null)
                                        .dealer(trade.getTrader())
                                        //TODO:允许配置多个人员
                                        //发起人如果未配置，取衡泰发起人
                                        .applicant(getOaUserAccount(context.getConfig(), trade, context.getOaAccountSet()))
                                        //债务融资工具,1银行间拆借
                                        .zwrzgj(1)
                                        .detailList(Collections.singletonList(
                                                TOaFlowXirTradeInfoZJYYBDto.TOaFlowXirTradeInfoDetailZJYYBDto.builder()
                                                        .czf(Objects.nonNull(party) ? party.getPartyname() : null)
                                                        //选项，1为等于
                                                        .xx(1)
                                                        //TODO:计算本息
                                                        .bx("以交易单为主")
                                                        .build()
                                        ))
                                        .jydslx("0")
                                        //附件处理，需要用到首期的配置
                                        //.fj(getFj(context, trade, existFstTradeInfoMap.get(trade.getIntordid())))
                                        .build();

                                if (!context.getBizType().equals(衡泰业务类型枚举_资金运营部.逆回购_首期)) {
                                    build.setFj(getFj(context, trade, existFstTradeInfoMap.get(trade.getIntordid())));
                                }

                                //同业拆借详情
                                TtrdOtcIblb iblb = iblbMap.get(trade.getIntordid());
                                if (Objects.nonNull(iblb)) {
                                    //如果存在交易明细单，根据具体业务类型重新计算
                                    build.setChangeAmount(context.getBizType().countChangeAmount(iblb));
                                    build.setSettleBeginDate(iblb.getFstsetdate());
                                    build.setSettleEndDate(iblb.getEndsetdate());
                                    build.setSettleDays(Integer.parseInt(iblb.getTerm()));
                                    build.setSettleFeeRate(new BigDecimal(iblb.getRate()));
                                    TOaFlowXirTradeInfoZJYYBDto.TOaFlowXirTradeInfoDetailZJYYBDto detailList = build.getDetailList().get(0);
                                    detailList.setRrje(build.getChangeAmount());
                                    detailList.setRrrq(iblb.getFstsetdate());
                                    detailList.setRrqx(Integer.parseInt(iblb.getTerm()));
                                    detailList.setLl(new BigDecimal(iblb.getRate()).multiply(new BigDecimal(100)) + "%");

                                }
                                build.setSyncTime(LocalDateTime.now());
                                build.setDeptTitle(getDeptTitle(build.getApplicant()));
                                return build;
                            })
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList())
            );
        }
    }

    /**
     * 获取附件
     */
    private static AppendIdDto getFj(BuildContext context, TtrdOtcTrade trade, TOaFlowXirTradeInfo fstInstTradeInfo) {
        if (context.getBizType().equals(衡泰业务类型枚举_资金运营部.逆回购_首期)) {
            return null;
        }
        if (Objects.isNull(fstInstTradeInfo) || StringUtils.isBlank(fstInstTradeInfo.getRequestId())) {
            logger.info("获取附件失败：未找到首期reqestid，intordid-{}，type-{}", trade.getIntordid(), trade.getTrdtype());
            return null;
        }
        //获取oa流程表单信息
        List<Map<String, String>> requestDataNew = null;
        try {
            requestDataNew = flowService.getRequestDataNew(fstInstTradeInfo.getRequestId(), null);
        } catch (Exception e) {
            logger.error("获取流程信息失败", e);
            return null;
        }
        //附件ids<url, fileName>
        Map<String, String> fjMap = new HashMap<>();
        requestDataNew.forEach(data -> {
            if (data.containsKey("flowInfos")) {
                JSONObject flowInfos = (JSONObject) JSON.parse(JSON.toJSONString(data.get("flowInfos")));
                if (flowInfos.containsKey("fj")) {
                    String urlStr = (String) flowInfos.get("fj");
                    String nameStr = (String) flowInfos.get(FlowService.APPENDIX_FILE_NAMES_FIELD);
                    List<String> urlList = Arrays.stream(urlStr.split(",")).collect(Collectors.toList());
                    List<String> nameList = Arrays.stream(nameStr.split(",")).collect(Collectors.toList());
                    //获取最小下标，防止越界
                    int minIdx = Math.min(urlList.size(), nameList.size());
                    for (int i = 0; i < minIdx; i++) {
                        fjMap.put(urlList.get(i), nameList.get(i));
                    }
                }
            }
        });
        if (CollectionUtil.isEmpty(fjMap)) {
            return null;
        }
        StringBuffer urlSb = new StringBuffer();
        StringBuffer nameSb = new StringBuffer();
        fjMap.forEach((urlStr, name) -> {
            ByteArrayOutputStream out = null;
            BufferedInputStream in = null;
            try {
                //先下载
                URL url = new URL(urlStr);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                in = new BufferedInputStream(connection.getInputStream());
                out = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = in.read(buffer, 0, buffer.length)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
                byte[] bytes = out.toByteArray();
                //在上传
                String newUrl = appendixService.updateAppendix(name, GatewayConstant.UP_FILE, bytes);
                urlSb.append(newUrl).append(",");
                nameSb.append(name).append(",");
            } catch (IOException e) {
                logger.error("异常", e);
                logger.error("获取文件异常，urlStr：" + urlStr + "，name：" + name);
            } finally {
                try {
                    if (Objects.nonNull(out)) {
                        out.close();
                    }
                    if (Objects.nonNull(in)) {
                        in.close();
                    }
                } catch (IOException e) {
                    logger.error("异常", e);
                    logger.error("获取文件异常，urlStr：" + urlStr + "，name：" + name);
                }

            }
        });
        if (urlSb.length() != 0 && nameSb.length() != 0) {
            urlSb.deleteCharAt(urlSb.length() - 1);
            nameSb.deleteCharAt(nameSb.length() - 1);
        }
        return new AppendIdDto(urlSb.toString(), nameSb.toString());
    }

    /**
     * 生产过程上下文
     */
    @SuperBuilder
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    @EqualsAndHashCode(callSuper = true)
    private static class BuildContext extends AbstractBuildContext<TOaFlowXirTradeInfoZJYYBDto> {
        @NotNull
        private 衡泰业务类型枚举_资金运营部 bizType;
        /**
         * 订单序号列表
         */
        @Nullable
        private List<String> intordIdList;
        /**
         * 指令列表（主要，只有同业拆入到期使用）
         */
        @Nullable
        private List<TtrdSetInstruction> instructionList;
        /**
         * 交易信息（同业拆入首期/到期）
         */
        @Builder.Default
        private List<TtrdOtcIblb> iblbList = new ArrayList<>(0);
        /**
         * 对手列表
         */
        @Builder.Default
        private List<TtrdOtcCounterparty> partyList = new ArrayList<>(0);
        /**
         * 质押债券
         */
        @Builder.Default
        private Map<String, List<TtrdOtcPledgebond>> pledgebondMap = new HashMap<>(0);

        @Builder.Default
        private Map<String, List<Tbnd>> tbndMap = new HashMap<>(0);
    }

    @Autowired
    public static void setLogger(Logger logger) {
        XirTradeZJYYBFactory.logger = logger;
    }

    @Autowired
    public void setOtcTradeRepo(TtrdOtcTradeRepository otcTradeRepo) {
        XirTradeZJYYBFactory.otcTradeRepo = otcTradeRepo;
    }

    @Autowired
    public void setInstructionRepo(TtrdSetInstructionRepository instructionRepo) {
        XirTradeZJYYBFactory.instructionRepo = instructionRepo;
    }

    @Autowired
    public void setXirTradeInfoRepo(TOaFlowXirTradeInfoRepository xirTradeInfoRepo) {
        XirTradeZJYYBFactory.xirTradeInfoRepo = xirTradeInfoRepo;
    }

    @Autowired
    public void setFlowService(FlowService flowService) {
        XirTradeZJYYBFactory.flowService = flowService;
    }

    @Autowired
    public void setAppendixService(AppendixService appendixService) {
        XirTradeZJYYBFactory.appendixService = appendixService;
    }

    @Autowired
    public void setIblbRepo(TtrdOtcIblbRepository iblbRepo) {
        XirTradeZJYYBFactory.iblbRepo = iblbRepo;
    }

    @Autowired
    public void setCounterpartyRepo(TtrdOtcCounterpartyRepository counterpartyRepo) {
        XirTradeZJYYBFactory.counterpartyRepo = counterpartyRepo;
    }

    @Resource
    public void setXirTradeService(TOaFlowXirTradeService xirTradeService) {
        XirTradeZJYYBFactory.xirTradeService = xirTradeService;
    }

    @Autowired
    public void setTtrdOtcPledgebondRepository(TtrdOtcPledgebondRepository ttrdOtcPledgebondRepository) {
        XirTradeZJYYBFactory.ttrdOtcPledgebondRepository = ttrdOtcPledgebondRepository;
    }

    @Autowired
    public void setTbndRepository(TbndRepository tbndRepository) {
        XirTradeZJYYBFactory.tbndRepository = tbndRepository;
    }

}
